Image Filter (ls-if.p) Object Replacement (ls-or.p) Displacement Map (ls-dm.p) Procedural Texture (ls-pt.p) Item Animation (ls-ia.p) Layout Generic (ls-gn.p)
With the notable exception of Layout Generic scripts, Layout scripting, on the other hand, presents a new method of script execution that causes an LScript to be activated only once, while it remains active until it is specifically stopped by either the termination of LightWave Layout, or the explicit deactivation of the Layout LScript plug-in from the plug-in panel. The script remains active even while you perform other functions within LightWave Layout. LightWave Layout scripts are designed to partake in this type of cooperative execution.
To facilitate this cooperative execution, Layout LScript scripting is centered completely around the concept of "call-back" functions. A call-back function is one designed to be called at any time, usually to respond to some specific event or situation. Until these call-back functions are activated, they remain "asleep," taking up no CPU time and having no influence on the processing of LightWave Layout.
Figure #1 illustrates the flow of execution in Modeler LScript.
Figure #1 Modeler LScript Execution Flow
Figure #2, however, illustrates the dramatic difference in execution flow for a Layout LScript.
Figure #2 Layout LScript Execution Flow
As mentioned previously, Layout Generic scripts are the exeception to this mechanism. The reason for this exception is that Layout Generic plug-ins are not associated with any Layout component (Camera, Mesh object, Light, etc.), and as such, are not involved in the generation of frames of animation. In fact, Layout Generic scripts behave almost identically to Modeler scripts in that they have a single point of entry, and their execution begins and ends with this function. Layout Generic scripts, however, have full access to all non-architecture-specific Layout components that all other Layout scripts enjoy. The section documenting Layout Generic LScripts later on this page provides more detail.
Having a clear understanding of these mechanisms is essential to the discussions that follow. Please take this time to examine the available example scripts for additional clarification, if necessary.
process() this call-back function is used to perform the main processing of the script, if any (similar to main() in Modeler scripting). it can be (and usually is) invoked more than once. create() called once when the script is loaded, immediately upon successful processsing of the script by the LScript core engine. it is used to perform "startup" processing for a script. destroy() called once when the script is deactivated from the plug-in panel or removed from memory. used to perform "cleanup" processing for a script. save() called when a scene file is saved to disk by the user. at this time, the script can store any script-related values to be restored when the scene is reloaded into LightWave Layout. in either a scene (ASCII) or object (binary) file. this function will be called each time the scene is saved to disk. load() used to restore any previously-saved script-related values from either a scene or object file options() invoked when the the "Options" button of the script is selected. standard requester functions, identical to those available in Modeler LScript, can be used to generate a user-interface and to allow the user to modify operational parameters. the LightWave Panel Services Global-Class plug-in must be available for successful requester dialog creation to occur. The LW Panel Services plug-in enables Layout LScript to offer several "extended" control types, discussed in Appendix C.A Layout script can define any of these "common" functions that it wishes to have activated. Once again, if one of these functions is not present in your script, Layout LScript will default its behavior (which is to say, an empty internal function is invoked instead). This is true even for the process() function.
Again, Layout Generic is the exception to these standards. Layout Generic
scripts have a single required function, generic()
, where processing
takes place when the script is activated. Refer to the
Layout Generic LScripts section later on this
page for more information.
The current globals available to Layout scripts are:
INSTANCE a read-only character string that represents an identifier that is guaranteed to be unique for each instance of a script, regardless of plug-in architecture.
Getfirstitem() returns a value that represents the first object of the type you desire. You select from the available object types by providing getfirstitem() with a parameter value (pre-defined by Layout LScript for convenience) that indicates the object list from which to pull. These pre-defined values are:
MESH select from among the available Layout mesh objects LIGHT select from among the defined Layout light sources CAMERA get a value that represents the Layout camera SCENE get a value that contains information about scene settingsGetfirstitem() will also accept a character string that should represent the name of an object that currently exist in Layout. This name should be identical to that displayed to the user in any object-selection panel within Layout.
Named objects can include Lights, Mesh data, or Bones.
filllight = getfirstitem("FillLight");You might have noticed that an access identifier for Bones is missing. The reason for this is that Bone objects are considered children of Mesh objects; Bones cannot exist by themselves. As such, access to Bone information must take place through the parent Mesh object. Bone objects essentially become data members of the LScript Mesh object.
As the name implies, getfirstitem() will return the first object (according to LightWave Layout) that resides in the list of the objects of the specified type. However, if no items of the specified type exist in the current scene, then getfirstitem() will return 'nil'. The following code snippet illustrates how you might use getfirstitem() to begin a sequential scan of the lights currently defined in the scene:
... light = getfirstitem(LIGHT); if light != nil then begin // scan through all lights ... end else // we're animating by Braille... ...The data type returned by getfirstitem() are "instances" of an internal LScript object type designed to provide an interface to, or "wrapper" around, the Layout object returned. Unlike normal LScript data types (string, integer, etc.), this data type is "alive." Not only does it provide access to data that is associated with the Layout object, but in most cases these object "instances" provide functions that you can invoke to perform some operation on the Layout object or its data. In the language of C++, these functions are referred to as "methods," and the object variables containing data are referred to as "data members." These "wrappers" for the Layout objects are known as Layout Object Agents in LScript parlance, but we will refer to them simply as Object Agents.
The LScript data type known as a "FileObject" is also a type of Object Agent, used as agents for disk files.
Getfirstitem() returns an Object Agent for the first Layout object, but it provides no capability for randomly accessing Layout objects, nor is there a companion function to getfirstitem() that will return the next Layout object in the list. How, then, do you access other objects of the same type?
Once you have the first Object Agent off the list, you have in your possession the ability to access all other Layout objects of that class in sequential order. Each Object Agent returned by a call to getfirstitem() provides (or "exports") some common functions (or "methods") that allow each Object Agent to perform the same functions--even though they my do so in different ways. In a purely object-oriented language like Smalltalk, these common methods are known as "messages" that an object recognizes and to which it can respond. When instances of different "classes" (definition of objects) respond to the same message, they are considered to be "polymorphic."
One such method that each Object Agent exports is called "next." The next() method will return the next Layout object (as a LScript Object Agent instance) in the list of the same object category. By way of example, let's see how we might accomplish a traversal of Layout Light objects in a Layout LScript script.
light = getfirstitem(LIGHT); while(light != nil) { ...code to process this light instance... light = light.next(); }Each Object Agent returned by getfirstitem() (or, for that matter, those returned by any Object Agent method that returns another Object Agent) will respond to the following common methods and contains the following common data members:
parent points to an Object Agent that represents the Layout object that is considered the parent of this Layout object (or 'nil' if there is none) target points to an Object Agent that represents the Layout object that is designated as the target for this Layout object (or 'nil' if there is none) type holds a constant (i.e., read-only) value that identifies the type of this Layout object (one of MESH, BONE, LIGHT, CAMERA, or SCENE) goal points to an Object Agent that represents the Layout object that is designated as the goal for this Layout object (or 'nil' if there is none) name holds a character string that represents the name of this Layout object (as it appears to the user in an Layout object list) getPosition(time) -> vector getRight(time) -> vector getUp(time) -> vector getForward(time) -> vector getRotation(time) -> vector getScaling(time) -> vector getPivot(time) -> vector getWorldPosition(time) -> vector getWorldRight(time) -> vector getWorldUp(time) -> vector getWorldForward(time) -> vector each of these methods returns a vector containing the three numeric values corresponding to the parameter at the specified time index. limits(state) -> array[6] returns an array of six (6) numbers that represent the minimum [elements 1-3] and maximum [elements 4-6] limits that have been established on a particular Layout object state (POSITION, RIGHT, UP, FOWARD, ROTATION, SCALING, PIVOT or WPOSITION) filename holds a character string that represents the filename (including path, if any) that contains this Layout object pointcount when appropriate, contains an integer value that represents the number of points in the Layout object, or 'nil' when not appropriate (i.e., CAMERA) polycount when appropriate, contains an integer value that represents the number of polygons in the Layout object, or 'nil' when not appropriate (i.e., CAMERA) shadows[] holds an array of three (3) boolean values that represent the Layout object's current shadow options: [1] == true if Self Shadow is on, or false if off [2] == true if Casts Shadow is on, or false if off [3] == true if Receive Shadow is on, or false if off dissolve(time) -> number returns the percentage (where 1.0 equals 100%) that this Layout object is dissolved at the specified 'time' index next() -> Object Agent returns the next Layout object (as a LScript Object Agent) in the list of the same category, or 'nil' if there is none firstChild() -> Object Agent returns a Object Agent that represents the Layout object that is designated as the first child belonging to this Layout object (or 'nil' if there is none) nextChild() -> Object Agent returns the next Object Agent that represents the Layout object that is designated as a child of this Layout object (or 'nil' if there is none) bone() -> Object Agent returns the first Object Agent that represents the Layout object that is designated as the first bone assigned to this Layout object (using the Object Agent method next(), you can traverse all Layout bones that are assigned to this Layout object)Because not all Layout objects contain the same types of data, some Object Agents will only offer a subset of these data members and respond to a subset of these exported methods. For instance, Object Agents of type SCENE will return 'nil' for most of these methods, and the CAMERA Object Agent contains no points or polygons.
A number of exported Object Agent methods listed previously accept a parameter that needs to be provided as a "time index." This index value represents the offset (expressed as time) from the beginning of the specific span of animation frames contained in the scene. To calculate the time index in which you have interest, simply divide the frame number by the frames-per-second setting for the scene. For instance, frame number 163 of a 30-frames-per-second animation would be the (163 / 30) second time index, or 5.43 seconds into the animation.
At the time of this writing, LightWave 3D is currently in its fifth major release, and as of LightWave 3D version 5.0, all data members discussed in this section are strictly read-only. Modifying them will have no effect on the Layout objects themselves, and will likely generate a run-time error when the script is executed.
flags[] holds an array of two (2) boolean values that represent the Bone's current options: [1] == true if Bone is active, or false if not [2] == true if Bone is limited, or false if unlimited restparam(state) -> array[3] returns an array of three (3) numbers that represent the value of a particular Bone state. The state value can be one of POSITION, RIGHT, UP, FORWARD, ROTATION, SCALING, PIVOT or WPOSITION ("world" position) restlength contains a floating-point number that represents the rest length of the Bone in meters innerlimit contains a floating-point number that represents the inner limit radius of the Bone (only valid if flags[2] is 'true') outerlimit contains a floating-point number that represents the outer limit radius of the Bone (only valid if flags[2] is 'true')
ambient(time) -> vector rgbambient(time) -> array[3] returns a vector or array of three (3) values that represent the global ambient Light's color values at the specified 'time' index. ambient() returns the channel value as a percentage between 0.0 and 1.0, while rgbambient() returns the channel value as an integer between 0 and 255. type holds a constant (read-only) integer value that identifies the type of this Light (one of DISTANTLIGHT, POINTLIGHT, or SPOTLIGHT) color(time) -> vector rgbcolor(time) -> array[3] returns a vector or array of three (3) values that represent the Light's color values at the specified 'time' index. color() returns the channel value as a percentage between 0.0 and 1.0, while rgbcolor() returns the channel value as an integer between 0 and 255. shadowtype holds a constant (read-only) integer value that identifies the shadow type of this Light (one of SHADOWRAYTRACE, SHADOWMAP or SHADOWOFF) coneangles[] holds an array of two (2) floating-point numbers that represent the cone angles for this Light if it is of type SPOTLIGHT. The first element [1] represents the radius as half the total Spotlight cone angle, and element [2] indicates the angular width of the Spotlight's soft edge.
zoomFactor(time) -> number returns a floating-point number that represents the Camera's zoom factor at the specified 'time' index focalLength(time) -> number returns a floating-point number that represents the Camera's focal length at the specified 'time' index focalDistance(time) -> number returns a floating-point number that represents (in meters) the Camera's focal distance at the specified 'time' index fStop(time) -> number returns a floating-point number that represents the Camera's f-stop setting at the specified 'time' index blurLength(time) -> number returns a floating-point number that represents (in meters) the Camera's blur length at the specified 'time' index fovAngles(time) -> array[2] returns an array of two (2) floating-point numbers that represent the Camera's field-of-view angles at the specified 'time' index. the first element [1] represents the horizontal angle, the second element [2] represents the vertical angle. these angles (measured in radians) are centered around the Camera's direction
name holds a character string that represents the name of this Scene filename holds a character string that represents the filename of this Scene totalpoints contains an integer value that represents the total number of Mesh points in the Scene totalpolygons contains an integer value that represents the total number of Mesh polygons in the Scene rendertype holds a constant (read-only) integer value that identifies the type of rendering that will take place in the Scene (one of WIRERENDER, QUICKRENDER, or REALISTICRENDER) renderopts[] holds an array of eight (8) boolean values that represent the Scene's current options: [1] == true if Shadow Tracing is active [2] == true if Reflection Tracing is active [3] == true if Refraction Tracing is active [4] == true if Field Rendering is active [5] == true if Reverse Field Rendering is active [6] == true if Motion Blur is active [7] == true if Depth-Of-Field is active [8] == true if Limited Region is active framestart contains an integer value that represents the beginning frame number to render frameend contains an integer value that represents the ending frame number to render framestep contains an integer value that represents the frame step value fps contains an integer value that represents the frames-per-second setting for the Scene (default is 30) framewidth contains an integer value that represents the width of the frames to be rendered frameheight contains an integer value that represents the height of the frames to be rendered pixelaspect contains a floating-point number that represents the pixel aspect ratio of the Scene (as pixel-width / pixel-height). minsamplesperpixel contains an integer value that represents the minimum number of samples per pixel in the final image based on the current rendering options. maxsamplesperpixel contains an integer value that represents the maximum number of samples per pixel in the final image based on the current rendering options. limitedregion[] holds an array of four (4) floating-point numbers that represent the location of the Scene's limited region area: [1] == x0 [2] == y0 [3] == x1 [4] == y1
options()
function, a Layout script can use requester code that
is virtually identical to that used by Modeler LScript. In fact, requester code can
actually be transferred between scripts without modification. However,
unlike Modeler, LightWave Layout does not contain integral interface code
that is made available to user-written plug-ins. Instead, Layout employs the
Panel Services plug-in to provide interface features to user-written plug-ins.
LScript takes advantage of the Panel Services plug-in to facilitate its own
requester functionality.Because Panel Services makes available controls that add more functionality than those found in LightWave 3D Modeler, Layout LScript passes this ability on to the Layout script writer in the form of new functions. Even though these new controls could be considered "non-standard", they have been designed within Layout LScript to function in a fashion similar to other controls.
Because Panel Services is a plug-in, the possibility exists that the plug-in may
not be available at the time your LScript attempts to post a requester panel.
To allow the script writer the ability to detect the absence of this critical
plug-in, the reqbegin()
command has been extended in Layout LScript
to return a logical 'true' or 'false' value to indicate the presence of the
Panel Services plug-in. A logical 'true' indicates its presence. You can use
this indicator to decide whether or not you have the required facilities to post
requesters from your script.
... if(!reqbegin("My Requester")) { error("Requester support unavailable"); return; } ...In support of Panel Services, five new control creation commands have been added to the Layout LScript command set. These functions are only available in Layout scripts; Modeler LScript does not support Panel Services-equivalents of these control commands.
ctlfilename(title,filename) -> string creates a control that contains an text edit field and a push button that will post a file-requester dialog box. the selection returned from the file requester will be placed into the text edit field. 'title' is a string value representing the label of the control 'filename' is a string value representing the initial value of the filename edit field of the control ctlrgb(title,rgb) -> vector creates a control that contains three numeric entry fields for typing in color components and a preview area where the entered values are combined and displayed. 'title' is a string value representing the label of the control 'rgb' is a vector value representing the Red, Green and Blue color components in the 'x', 'y', and 'z' positions. each of these values is an integer number between 0 and 255. This parameter can also be a single integer value that will be used with all channels, or it can be three individual integer values corresponding to each of the color channels. ctlhsv(title,hsv) -> vector creates a control that contains three numeric entry fields for typing in color components and a preview area where the entered values are combined and displayed. 'title' is a string value representing the label of the control 'hsv' is a vector value representing the Red, Green and Blue color components in the 'x', 'y', and 'z' positions. each of these values is an integer number between 0 and 255. This parameter can also be a single integer value that will be used with all channels, or it can be three individual integer values corresponding to each of the color channels. ctlcheckbox(title,state) -> boolean 'title' is a string value representing the label of the control 'state' is a boolean value that indicates the appearance of the checkbox. a logical 'true' will initially check the control, while a logical 'false' will leave it unchecked ctlallitems(title) -> Object Agent ctlmeshitems(title) -> Object Agent ctlcameraitems(title) -> Object Agent ctllightitems(title) -> Object Agent ctlboneitems(title) -> Object Agent ctlimageitems(title) -> Object Agent these functions create controls that provide a drop-down list of the specified types of Layout objects currently available in the scene. the return value from each of these controls is an Object Agent that represents the LightWave object that was selected, or 'nil' if no object was selected. 'title' is a string value representing the label of the control
Because we will be dealing with and discussing internal data structures that LightWave 3D makes publicly available to plug-ins, it is assumed that you have some level of familiarity with the data structures and mechanisms that are employed by 3D rendering systems and some of the more common computer graphics file formats being used in the industry today (i.e., Targa).
There are a number of different data buffers that Layout uses or creates as a result of its rendering activity, and your LS/IF script can request access to any or all of these buffers. Regardless of which buffers you request, however, all LS/IF scripts have implicit access to the Red, Green, Blue and Alpha-Channel buffers maintained by Layout. You do not have to explicitly request these buffers.
With the exception of the implicit buffers (Red, Green, etc.), all Layout-maintained buffers are strictly read-only. Their contents are intended to be used to influence your modifications of those buffers whose data are meant to be altered.
The buffers to which a LS/IF script can request access are:
RED, GREEN, BLUE, ALPHA these buffers are available to every script, and represent the individual RGB and Alpha values of the rendered frame. off all buffers available, only these may be modified. all others are strictly read-only SPECIAL this value is assigned by the user on a surface by surface basis which is used only for this filter. this is designed to be used to activate the post-processing effect for specific surfaces, and user-assigned percentages show up here as 0-255 values in the buffer LUMINOUS, DIFFUSE, MIRROR, TRANS, RAWRED, RAWGREEN, RAWBLUE these eight buffers are the raw values of the surface parameters before shading SHADING this buffer is a picture of the diffuse shading applied to the raw shapes in the image SHADOW this buffer indicates where shadows are falling in the final image. it may also be thought of as an illuminations map, showing what parts of the image are visible to the lights in the scene GEOMETRY the values in this buffer are computed from the dot-product of the surface normal with the eye vector. it reveals something about the underlying shape of the objects in the image. where this buffer is 255 (or 1.0) the surface is facing directly toward the camera, and where this buffer is 0, the surface is edge-on to the camera DEPTH this buffer is a map of the distance of each pixel from the camera plane. this buffer differs from all the others in that it is floating point, and because it is not anti-aliased or motion-blurredYou can communicate to Layout the buffers it should make available to your script by returning one or more of these pre-defined values from your flags() function. In fact, the sole purpose of the flags() function is to do nothing but return one or more of these values. For example, the following code snippet illustrates a sample flags() function used to merely consume CPU time by requesting the implicit buffers:
flags { return(RED, // select the defaults just for fun GREEN, BLUE, ALPHA); }Processing Image Buffers
As with most Layout scripts, the central point of processing in a LS/IF script takes place in the process() function. The process() function is invoked only once for every frame of animation that LightWave 3D Layout generates, and any manipulations the script is designed to apply to the image pixels should be rendered to the entire image at that time.LS/IF passes five parameters to the process() function when it is invoked. These parameters are designed to assist the process() function in accessing data in the Layout buffers by providing such information as the image width and height, as well as the current frame number being rendered. The five parameters passed to a LS/IF process() function are listed below.
width an integer value that indicates the width (number of horizontal lines) of the generated image. this value will be equal to the value that the user has set under the Layout Camera information panel. height an integer value that indicates the height (number of vertical lines) of the generated image. this value will be equal to the value that the user has set under the Layout Camera information panel. frame an integer value that indicates the frame number of the generated image start a floating-point number that represents the start time of this frame as a time index value. end a floating-point number that represents the end time of this frame expressed as a time index value. this index value will be the same as the start time unless the frame has had motion-blur apply by Layout. In this case, the difference between the starting and ending time index is the "exposure time" for the frameLS/IF scripts can call upon specialized, internal functions for accessing and updating the Red, Green, Blue and Alpha-Channel image buffer data. These functions are only available to a LS/IF function, and are not shared among other Layout scripts.
bufferline(bufferid,line) -> array[] used to retrieve the values in the buffer identified by 'bufferid' for the indicated vertical image 'line'. 'bufferid' is one of the buffer indicators discussed previously (SPECIAL, DIFFUSE, RED, etc.). if a buffer is requested that was not selected in the flags() function, a run-time error will occur. returns an array of buffer values whose count of elements matches the 'width' parameter passed to the process() function floatline(bufferid,line) -> array[] this function is identical to bufferline(), except that it is used to access buffers that contain floating-point data (currently only the DEPTH buffer qualifies) setrgb(col,row,buf) used to set the Red, Green and Blue value for a particular image pixel at the specified row/column of the image. 'buf' is an array of three color values that represent Red ([1]), Green ([2]) and Blue ([3]) setalpha(col,row,bufval) used to set the Alpha value for a particular image pixel at the specified row/column of the image processrgb(row,red,green,blue,alpha) this function is a replacement for both the setrgb() and setalpha() functions, and will process all four buffers at once for the specified image row. because individual buffer elements are processed all at once--instead of one at a time, as is the case with setrgb() and setalpha()--this function tends to be much fasterPlease note that, as in all cases concerning LScript arrays, the values that you use as image row/column indicators should always be "1-based", meaning that the first element in each buffer is always [1]. If you attempt to access the first element as [0], a run-time error will be generated, and the LS/IF script will disable itself from further activation.
Caching Image Data
As the name implies, Image Filter plug-ins are quite literally filters. Data comes in one end from Layout, and passes out the other end directly back to Layout. When you callbufferline()
to retrieve a copy of the data in Layout's render buffer, you must process that line, and pass it back to Layout using any one of the available processing commands. In a typical processing situtation, however, once you pass this modified data back to Layout, you cannot access it again. Further calls tobufferline()
requesting the same scan-line will simply return to you the original, unmodified scan-line data. The image data you modified is now safely tucked away into a separate buffer, forever beyond your reach.LS/IF provides an internal mechanism to script writers that will take the rendered image data provided by Layout and cache it locally. This allows for such procedures as processing image data in multiple passes, or processing only portions of the image without having to cycle through all of the data. This mechanism does not necessarily provide speed improvements to LS/IF scripts; rather it provides convenience to the script writer.
To enable this caching feature, place a call to the following function at the head of your LS/IF script's
process()
function:
cache() this function causes the LS/IF script instance to acquire all rendered image data into the local memory space of the script to facilitate multiple accesses to the same data.Once you have enabled caching, all other LS/IF commands and functions are used just as though you were performing true filtering. However, these function calls will be redirected to retrieve and update the local data within the script instance instead of the data being buffered by Layout.When caching is enabled, two new functions become available that allow direct row/column access to pixel data. These functions are only active when and after the cache() call is made in your Image Filter script.
getpixel(row,col) -> array[4] this function accepts row and column integer values, specifying an exact location in the pixel data buffer. it returns the Red, Green, Blue, and Alpha values at that location. putpixel(row,col,red,green,blue,alpha) pixel data can be directly modified using this value. the pixel values at the specified row and column offset in the pixel buffer will be altered to reflect the values provided for the Red, Green, Blue, and Alpha channels.There is no need to explicitly "flush" the new internal image data once caching is enabled. The LS/IF plug-in will automatically perform a complete update to Layout of the modified data when your script'sprocess()
function terminates.
LS/IF Logic Flow
Here we will examine the flow of control that passes through a LS/IF script as it is invoked by LightWave Layout.The sequence of processing within a LS/IF script will typically begin with the flags() function. Remember that this function is optional, and if you do provide a flags() function in your script, then only the Red, Green, Blue and Alpha-Channel buffers will be available for access later in your process() function. For the sake of illustration, we call once again upon our space- consuming flags() function that selects the implicit buffers:
flags { return(RED,GREEN,BLUE,ALPHA); }If your script is active, Layout attempts to add your processing to the rendered image by invoking your process() function. This will typically occur immediately after the image has been rendered, but before it is displayed to the user or saved to disk. Here is an incomplete process() function that shows the typical flow of processing that a script will want to duplicate for each image:
process: width, height, frame, starttime, endtime { out[3] = nil; // holds new values passed back to Layout for(i = 1;i <= height;++i) { red = bufferline(RED,i); green = bufferline(GREEN,i); blue = bufferline(BLUE,i); alpha = bufferline(ALPHA,i); for(j = 1;j <= width;++j) { // perform some manipulation on the buffer values ... setrgb(j,i,out); setalpha(j,i,alpha[j]); } } }It should be noted that, whether or not you perform any modifications to a particular image pixel or Alpha-Channel value, unless you have enabled caching with a call tocache()
, a call to setrgb() and setalpha() (or, alternately, processrgb()) must be made. As the name implies, LS/IF is an image filter, and like all filters, things are expected to enter, while something useful passes through to eventually emerge in the output. LightWave Layout expects every pixel of the Red, Green, Blue and Alpha-Channel buffers to pass through this filter in order to generate a complete image. If you fail to process a pixel into Layout's output--whether or not you altered its value--then the resulting location in the final image will have an undefined value RGB (typically, each channel is assigned zeros (0), which equates to black in the output).
Using The Monitor
Unique among Layout LScript plug-ins, LS/IF provides access to a progress monitor, quite similar to that offered by Modeler LScript. Because a great deal of processing can take place inside an Image Filter plug-in (imagine having to perform some function on each pixel of a 640x480 image for each frame of animation!), a visual indicator is used to provide feedback to the viewer concerning the progress of processing.The following functions are used to manage Layout-provided monitor access. As you will see, usage of these functions is almost identical to those provided within Modeler LScript.
moninit(steps) initializes the monitor system, indicating the anticipated number of steps required to complete the processing task monstep([advance]) advances the monitor indicator by the optional integer value provided. if no argument is provided, then the advance value is 1 monend() terminates the monitor system //// //// //// //// //// //// //// //// //// //// /// /// // S T A R T C O N S T R U C T I O N // / / //// //// //// //// //// //// //// //// ////LS/PT (Procedural Texture)
Procedural textures (or Shaders, as they are commonly referred to) are surface appearances that are calculated at render-time based upon specific values. LS/PT is a shader scripting plug-in, and can be used to give a surface a desired texture or color.The included example script, Blotch, creates a colored spot on a surface.
Shader Functions
LS/PT contains two of its own specific support functions.
init() invoked at the start of a sequence of frames. use to initialize script values that are needed to properly generate a texture cleanup() invoked when a render sequence is complete newtime(frame,time) invoked at the start of each new time within the current render sequence. an integer value 'frame' indicates the current frame number, while the number 'time' specifies the current time index flags() a LS/PT script needs to indicate to Layout which attributes of a surface's texture it will modify. one or more of the following values may be returned from the flags() function: NORMAL COLOR LUMINOUS DIFFUSE SPECULAR MIRROR TRANSPARENT ETA ROUGHNESS RAYTRACE if a LS/PT script intends to utilize the raytrace() method (discussed presently), then it should include in the flags() return value the RAYTRACE flag.Processing Textures
As with all Layout scripts, the processing point of your LS/PT script is the process() function. The process() function is called on a per-pixel basis.LS/PT provides a single argument to your script's process() function. This argument is an instance of a Object Agent, known as a ShaderObject. This object contains data members and methods that can be accessed (and in some cases, modified).
A LS/PT ShaderObject has the following members/methods:
sx (READ-ONLY) number representing the spot X location in the final image in pixel coordinates where (0,0) is at the upper-left corner sy (READ-ONLY) number representing the spot Y location in the final image in pixel coordinates where (0,0) is at the upper-left corner oPos[3] (READ-ONLY) numbers that represent theTo set the perceived color directly, a shader script can set all the parameters to zero except for luminous which is 1.0 and color which is the output color of the spot.coordinates of the spot position in object coordinates wPos[3] (READ-ONLY) numbers that represent the coordinates of the spot position in world coordinates gNorm[3] (READ-ONLY) numbers representing the geometric normal of the spot in world coordinates. this is the raw polygonal normal at the spot, unperturbed by smoothing or bump mapping spotSize (READ-ONLY) number representing the approximate spot diameter. this is a very approximate value since spots on a surface viewed on edge are long and thin. this can be used to compute texture anti-aliasing raySource[3] (READ-ONLY) numbers representing the origin of the incoming viewing ray in world coordinates. often this will be the camera but it does not have to be rayLength (READ-ONLY) a number representing the distance the viewing ray travelled in free space to reach this spot cosine (READ-ONLY) a number representing the cosine of the angle between the viewing ray and the surface normal at this spot. it indicates how glancing the view is and gives a measure of how approximate the spot size is oXfrm[9] (READ-ONLY) object-to-world transformation matrix. this can be computed other ways, but are included here for speed and are intended to be used primarily for directional vectors. wXfrm[9] (READ-ONLY) world-to-object transformation matrix. This can be computed other ways, but are included here for speed and are intended to be used primarily for directional vectors. objID (READ-ONLY) a pointer to an Object Agent that represents the object being shaded polNum (READ-ONLY) an integer that represents the polygon number of the object being shaded. While this will be the polygon number for normal mesh objects, it may represent other sub-object information in non-mesh objects. wNorm[3] new geometric normal of the spot in world coordinates. Modifying this makes the surface look bumpy without altering the geometry (bump mapping). The shader needs to re-normalize the vector after perturbation. color[3] numbers representing the percentage of the Red [1], Green [2], and Blue [3] values of the surface color, where 1.0 equals 100% luminous a number representing the percentage of luminousity of the surface (1.0 == 100%) diffuse a number representing the percentage of diffusion of the surface (1.0 == 100%) specular a number representing the percentage of specularity of the surface (1.0 == 100%) mirror a number representing the percentage of mirroring of the surface (1.0 == 100%) transparency a number representing the percentage of transparency of the surface (1.0 == 100%) eta a number representing the percentage of the index of refraction of the surface (1.0 == 100%) roughness a number representing the percentage of roughness of the surface (1.0 == 100%)
ShaderObject Methods
ShaderObject's provide two methods can be used in generating a surface texture.
illuminate(light,position) -> array[6] this function returns an array of six (6) numbers that represent the light ray (color[1-3] and direction[4-6]) hitting the given position from the given light at the current instant. the return value is zero if the light does not illuminate the given world coordinate position at all. the color includes effects from shadows (if any), falloff, spotlight cones and transparent objects between the light and the point raytrace(position,direction) -> array[4] this function may be called to trace a ray from the a given location in a given direction (in world coordinates). the function returns an array of four (4) elements that represent the length of the ray [1] and the color coming from that direction [2-4]. the ray length will be -1.0 if it is infinite. the direction used is the outgoing direction and must be normalized to be a unit vectorLS/DM (Displacement Map)
The LS/DM plug-in is used to calculate the location of an object's point based on a given frame and/or time. Unlike LS/IF, whose processing can be accomplished in a single invocation, a LS/DM script is called on a per-point basis.
Displacement Functions
LS/DM offers the following displacement-specific functions:
newtime(object,frame,time) as with LS/PT, this function is invoked at the start of each new time within the current sequence. the parameters provided to newtime() are: an Object Agent that represents the object containing the point to be processed; an integer representing the frame number; and a number representing the current time index. flags() this function returns (only) one of two possible values, that indicate whether displacements will take place in world coordinates (WORLD) or in the object's local coordinates (LOCAL)Processing Displacement
The LS/DM process() function is provided with a single argument. This argument is an instance of a DisplacementObject.A LS/DM DisplacementObject contains the following data members:
oPos[3] (READ-ONLY) numbers representing theNo methods are provided by the DisplacementObject.position of the point being processed at its origin. these values do not change, and should be used to calculate offsets based upon the passage of time source[3] numbers representing the new position of the point being processed for the current frame/time LS/IA (Item Animation)
LS/IA, an Item Animation plug-in, allows you to influence an object's translations during an animation sequence. You can modify an object's position, rotation, and scaling, overriding that calculated by Layout.
Processing Motion
LS/IA provides three arguments to the process() function. The second and third parameters are the integer frame number and numeric time index of the current invocation. The first argument is an instance of a MotionObject.The LS/IA MotionObject provides the following object methods:
get(attribute,time) -> vector this function will return a vector that represents the value of the specified 'attribute' at the given 'time'. 'attribute' can be one of POSITION, ROTATION, or SCALING. 'time' is the time index in which you are interested. in the case of ROTATION, theA LS/IA MotionObject contains the following data members:values are in degrees. SCALING values are multipliers, where 1.0 indicates no change. set(attribute,value) this function allows you to set the specified 'attribute' (POSITION, ROTATION, SCALING) to the provided vector 'value'
objID (READ-ONLY) a pointer to the Object Agent to which this particular plug-in has been assignedLS/OR (Object Replacement)
LS/OR allows you to arbitrarily replace an object in Layout on a frame-by-frame basis.
Processing Replacements
The process() function of a LS/OR plug-in receives a single argument. This argument is an instance of a ReplacementObject. The LS/OR ReplacementObject provides the following data members:
objID (READ-ONLY) an Object Agent that represents the object whose geometry you are replacing curFrame (READ-ONLY) an integer that represents the frame number for the currently loaded geometry. curTime (READ-ONLY) a number that represents the time index for the currently loaded geometry. newFrame (READ-ONLY) an integer value that represents the frame number for the next step. new geometry should be loaded if the object needs to look different at this new frame newTime (READ-ONLY) a number that represents the time index for the next step. new geometry should be loaded if the object needs to look different at this new time index. 'curTime' and 'newTime' may not be sequential, since network rendering can cause the renderer to jump around between non-sequential times curType (READ-ONLY) a constant value that indicates the current type of rendering to be done. the script can provide different geometry for interactive previewing and actual rendering by examining this value. this value can be one of NONE, PREVIEW, or RENDER. NONE is present if no geometry is loaded for the current time index. PREVIEW indicates that a Layout preview is being generated, where RENDER is used when a complete render is being done newType (READ-ONLY) a constant that indicates the type of rendering that will be done at the next frame/time index. this member can be one of NONE, PREVIEW, or RENDER curFilename (READ-ONLY) a string value that represents the object geometry file currently loaded, and may be 'nil' if there is no geometry loaded. newFilename a string value that represents the filename of a new object file to be loaded as the geometry for this item at the new time index, and is the only data member set by the script. it should only be set if the new geometry differs from that currently loaded, since loading new geometry incurs significant overhead //// //// //// //// //// //// //// //// //// //// /// /// // E N D C O N S T R U C T I O N // / / //// //// //// //// //// //// //// //// ////LS/GN (Layout Generic)
Finally, we come to Layout Generic scripting. LS/GN allows you to access Layout internal objects and data without the need to be associated with any scene or scene component. Layout Generic scripts can access all scene components and settings, as well as all functions and data belonging to the LScript engine (preprocessor, Requester support, IPC queues, etc.).
Generic Script Construction
Layout Generic scripts are very similar to the format used by Modeler scripts. There is a single, required function in all Layout Generic scripts, and this function is calledgeneric()
. When a Layout Generic script is invoked, execution will begin with this function, and when this function terminates, execution of the script will be complete.Here is a simple Layout Generic script to report on the number of vertices in an object currently loaded into Layout:
generic { if(!reqbegin("Point Count")) return; // no Panel Services plug-in c1 = ctlallitems("Reference object"); if(reqpost()) { if((item = getvalue(c1)) == nil) return; } else return; reqend(); info("Object ",item.name," has ",item.pointcount," points."); }Generic Functions
The Layout Generic architecture makes available two functions for managing Layout scenes:
loadscene(filename[,title]) this function loads the indicated 'filename' as a Layout scene file. the optional 'title' parameter will be used to name the scene file internally once it is loaded. this optional name will then become the scene's new filename. if this parameter is not provided, the 'filename' parameter will be used in it's place. savescene(filename) this function saves the scene that is currently loaded into Layout as the provided path and 'filename'.
Next Section Previous Section Table of Contents Index Errata
© 1996 Virtual Visions, Inc.
© 1997 NewTek, Inc.